package com.xiaobai.waitAndNodify;

import com.xiaobai.util.ThreadUtil;
import lombok.extern.slf4j.Slf4j;

/*
同步模式之保护性暂停
jdk中的join的实现 和Future的实现都是基于保护性暂停的
一个线程等待另外一个线程的执行结果
 */
@Slf4j
public class GuardedSuspension {
    //线程1 等待 线程2的下载结果
    // 1.好处是在join的时候 只能等待别的线程执行结束之后 才能进行操作
    // join是需要等待线程完全结束后才能进行操作
    // 而保护性暂停是还是可以进行下面代码的执行的 不需要等待线程完成结束的 对于线程t2来说

    //2.join等待结果是需要全局的 而不能是局部的
    public static void main(String[] args) {
        GuardedObject guardedObject = new GuardedObject();
        new Thread(() -> {
            log.debug("等待下载结果");
            guardedObject.waitResponse(2000);
            log.debug("下载完成");
        },"t1").start();
        new Thread(() -> {
            log.debug("开始上传");
            ThreadUtil.sleep(1);
            guardedObject.complete(null);
            log.debug("上传完成");
        },"t2").start();

    }
}
@Slf4j
class GuardedObject {
    private Object response;

    //获取结果
    synchronized public Object waitResponse() {
        while (response == null) {
            try {
                wait();
            } catch (InterruptedException e) {
                log.error(e.getMessage() );
            }
        }
        return response;
    }

    synchronized public Object waitResponse(long timeout) {
        //开始时间
        long startTime = System.currentTimeMillis();
        //需要经历的时间
        long passTime = 0;
        while (response == null) {
            //还需要等待的时间
            long waitTime = timeout - passTime;
            if (waitTime <= 0) {
                log.debug("超时等待结束了");
                break;
            }
            try {
                wait(waitTime); //不应该是等待timeout 因为还是存在虚假唤醒的 这个时候就不是休眠这么久了
            } catch (InterruptedException e) {
                log.error(e.getMessage() );
            }
             passTime = System.currentTimeMillis() - startTime;
        }
        return response;
    }

    //设置结果
    public synchronized void complete(Object response) {
        this.response = response;
        this.notifyAll();
    }
}